package run.bottle.authserver;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
import run.bottle.urp.model.po.Permission;
import run.bottle.urp.model.po.Role;
import run.bottle.urp.model.po.User;
import run.bottle.urp.service.PermissionService;
import run.bottle.urp.service.RoleService;
import run.bottle.urp.service.UserService;

import java.time.Duration;
import java.util.UUID;

@SpringBootApplication
public class AuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AuthServerApplication.class, args);
    }

    @Bean
    CommandLineRunner run(UserService userService, RoleService roleService, PermissionService permissionService,
                          RegisteredClientRepository registeredClientRepository, PasswordEncoder passwordEncoder) {
    return args -> {
            roleService.saveRole(new Role(null, "ROLE_USER", "", 1));
            roleService.saveRole(new Role(null, "ROLE_MANAGER", "", 1));
            roleService.saveRole(new Role(null, "ROLE_ADMIN", "", 1));
            roleService.saveRole(new Role(null, "ROLE_SUPER_ADMIN", "", 1));

            userService.saveUser(new User(null, "user", "password", "user@bottle.run","1","155","user@bottle.run","","","1",false));
            userService.saveUser(new User(null, "admin", "password", "admin@bottle.run","1","155","admin@bottle.run","","","1",false));
            userService.saveUser(new User(null, "liyc", "123456", "liyc@bottle.run","1","155","liyc@bottle.run","","","1",false));

            userService.addRoleToUser("user", "ROLE_USER");
            userService.addRoleToUser("admin", "ROLE_USER");
            userService.addRoleToUser("admin", "ROLE_ADMIN");
            userService.addRoleToUser("liyc", "ROLE_USER");
            userService.addRoleToUser("liyc", "ROLE_ADMIN");
            userService.addRoleToUser("liyc", "ROLE_SUPER_ADMIN");

            permissionService.save(new Permission(null,null,"message:get","测试接口1","1","","GET","/message","/message",1,2,true,true));
            permissionService.save(new Permission(null,null,"message:post","测试接口2","1","","POST","/message","/message",1,2,true,true));

            permissionService.addPermissionToRole("message:get", "ROLE_USER");

            permissionService.addPermissionToRole("message:get", "ROLE_ADMIN");
            permissionService.addPermissionToRole("message:post", "ROLE_ADMIN");

            permissionService.addPermissionToRole("message:get", "ROLE_SUPER_ADMIN");
            permissionService.addPermissionToRole("message:post", "ROLE_SUPER_ADMIN");

            initClientRepository(registeredClientRepository, passwordEncoder);
    };
    }


    private void initClientRepository(RegisteredClientRepository registeredClientRepository, PasswordEncoder passwordEncoder) {

        // 设置token有效时长
        TokenSettings tokenSettings = TokenSettings.builder()
                .accessTokenTimeToLive(Duration.ofMinutes(30)).build();

        RegisteredClient loginClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("login-client")
                .clientSecret(passwordEncoder.encode("openid-connect"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .redirectUri("http://127.0.0.1:8080/authorized")
                .scope(OidcScopes.OPENID)
                .scope("message.read")
                .scope("message.write")
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();
        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("messaging-client")
                .clientSecret(passwordEncoder.encode("secret"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .scope("message.read")
                .scope("message.write")
                .build();
        RegisteredClient userClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("user-client")
                .clientSecret(passwordEncoder.encode("user-secret"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .tokenSettings(tokenSettings)
                .scope("message.read")
                .scope("message.write")
                .build();
        RegisteredClient bottleClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("bottle-client")
                .clientSecret(passwordEncoder.encode("bottle-secret"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .tokenSettings(tokenSettings)
                .scope("message.read")
                .scope("message.write")
                .build();

        if (registeredClientRepository.findByClientId(loginClient.getClientId()) == null) {
            registeredClientRepository.save(loginClient);
        }
        if (registeredClientRepository.findByClientId(registeredClient.getClientId()) == null) {
            registeredClientRepository.save(registeredClient);
        }
        if (registeredClientRepository.findByClientId(userClient.getClientId()) == null) {
            registeredClientRepository.save(userClient);
        }
        if (registeredClientRepository.findByClientId(bottleClient.getClientId()) == null) {
            registeredClientRepository.save(bottleClient);
        }

    }
}
